/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Protected Byte Array Class
 *      Provides a definition for a memory-protected byte array value.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using Adaptive.Foundation;

namespace Adaptive.Foundation.Security
{
    /// <summary>
    /// Provides a definition for a memory-protected byte array value.
    /// </summary>
    public sealed class ProtectedByteArray : DisposableObjectBase
    {
        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations
        /// <summary>
        /// Protected memory value.
        /// </summary>
        private byte[] _protectedValue;
        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <value>
        /// This is the default constructor.
        /// </value>
        public ProtectedByteArray()
            : base()
        {
        }
        /// <summary>
        /// Initializes a new instance of the class for the specified
        /// byte array value.
        /// </summary>
        /// <param name="value">
        /// The byte array containing the value to store and protect.
        /// </param>
        public ProtectedByteArray(byte[] value)
            : base()
        {
            Value = value;
        }
        /// <summary>
        /// Deallocates internally allocated objects.
        /// </summary>
        /// <param name="disposing">
        /// A value indicating whether the object is being disposed.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            if ((!Disposed) && (disposing))
            {
                if (_protectedValue != null)
                {
                    UnlockData();
                    Array.Clear(_protectedValue, 0, _protectedValue.Length);
                    _protectedValue = null;
                }
            }
            _protectedValue = null;
            base.Dispose(disposing);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets or sets the value being stored in memory.
        /// </summary>
        /// <value>
        /// A byte array value to store in memory.
        /// </value>
        public byte[] Value
        {
            get
            {
                byte[] returnValue = null;				//Return value.

                //Read the value if present; otherwise, return null.w
                if (_protectedValue != null)
                    returnValue = ReadStoredData();

                return returnValue;
            }
            set
            {
                //Clear current content, if present.
                if (_protectedValue != null)
                {
                    UnlockData();
                    Array.Clear(_protectedValue, 0, _protectedValue.Length);
                    _protectedValue = null;
                }

                //Set current value.
                if (value == null)
                    _protectedValue = null;
                else
                    StoreData(value);
            }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Methods
         *------------------------------------------------------------------------------*/
        #region Private Methods
        /// <summary>
        /// Unprotects the internal memory storage.  
        /// </summary>
        private void UnlockData()
        {
            if (_protectedValue != null)
            {
                try
                {
                    ProtectedMemory.Unprotect(_protectedValue, MemoryProtectionScope.SameProcess);
                }
                catch
                {
                }
            }
        }
        /// <summary>
        /// Stores the value in memory.
        /// </summary>
        /// <param name="dataValue">
        /// The clear byte array to be stored.
        /// </param>
        private void StoreData(byte[] dataValue)
        {
            //Set to null of original parameter is null.
            if (dataValue == null)
                _protectedValue = null;
            else
            {
                //Copy the original.
                _protectedValue = new byte[dataValue.Length];
                Array.Copy(dataValue, _protectedValue, dataValue.Length);

                //Protected the private storage.
                ProtectedMemory.Protect(_protectedValue, MemoryProtectionScope.SameProcess);
            }
        }
        /// <summary>
        /// Reads the data from protected memory.
        /// </summary>
        /// <returns>
        /// A byte array or <b>null</b> if not set.
        /// </returns>
        private byte[] ReadStoredData()
        {
            byte[] returnValue = null;				//Return value.

            if (_protectedValue != null)
            {
                //Temporarily un-protect the data.
                ProtectedMemory.Unprotect(_protectedValue, MemoryProtectionScope.SameProcess);

                //Copy the value content.
                returnValue = new byte[_protectedValue.Length];
                Array.Copy(_protectedValue, returnValue, returnValue.Length);

                //Re-protect the data.
                ProtectedMemory.Protect(_protectedValue, MemoryProtectionScope.SameProcess);
            }
            return returnValue;
        }
        #endregion
    }
}